#include "pdf.h"
#include "util.h"

double SpherePdf::value(const Vec3& direction) const
{
    return 1 / (4 * pi);
}

Vec3 SpherePdf::generate() const
{
    return random_unit_vector();
}

CosinePdf::CosinePdf(const Vec3& w)
{
    uvw.build_from_w(w);
}

double CosinePdf::value(const Vec3& direction) const
{
    auto cosine_theta = dot(unit_vector(direction), uvw.w());
    return fmax(0, cosine_theta / pi);
}

Vec3 CosinePdf::generate() const
{
    return uvw.local(random_cosine_direction());
}

Pdf::~Pdf()
{
}

HittablePdf::HittablePdf(const Hittable& objects, const Point3& origin)
    : objects(objects), origin(origin)
{
}

double HittablePdf::value(const Vec3& direction) const
{
    return objects.pdf_value(origin, direction);
}

Vec3 HittablePdf::generate() const
{
    return objects.random(origin);
}

MixturePdf::MixturePdf(shared_ptr<Pdf> p0, shared_ptr<Pdf> p1)
{
    p[0] = p0;
    p[1] = p1;
}

double MixturePdf::value(const Vec3& direction) const
{
    return 0.5 * p[0]->value(direction) + 0.5 * p[1]->value(direction);
}

Vec3 MixturePdf::generate() const
{
    if (random_double() < 0.5)
        return p[0]->generate();
    else
        return p[1]->generate();
}
